package com.mathdroid.gui.main.browser;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.Box;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import com.mathdroid.model.EModelObserverEvent;
import com.mathdroid.model.IModelObserver;
import com.mathdroid.model.Model;
import com.mathdroid.model.enums.EItemSlot;
import com.mathdroid.model.enums.EItemType;
import com.mathdroid.model.enums.EModuleProficiency;
import com.mathdroid.model.enums.EWeaponProficiency;
import com.mathdroid.model.items.ItemBrowserModel;

/**
 * This panel gives the option to browse items and compare them.
 */
public final class BrowserPanel extends JPanel implements IModelObserver {
	/**
	 * Default UID.
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Scroll pane for the item browser.
	 */
	private JScrollPane scrollpane = null;
	
	/**
	 * Filter bar.
	 */
	private final JMenuBar filterBar = new JMenuBar();
	
	/**
	 * The item browser.
	 */
	private final ItemBrowser content = new ItemBrowser(null, null);
	
	/**
	 * Constraints for this tab.
	 */
	private final GridBagConstraints c = new GridBagConstraints();
	
	/**
	 * The menu to select slots.
	 */
	private JMenu filterMenu = new JMenu();
	
	/**
	 * The width of the item search field.
	 */
	private static final int SEARCH_FIELD_WIDTH = 100;

	/**
	 * The height of the item search field.
	 */
	private static final int SEARCH_FIELD_HEIGHT = 20;
	
	/**
	 * Create the item browser tab.
	 */
	public BrowserPanel() {
		this.setLayout(new GridBagLayout());
		
		Model.registerObserver(this);
		
		this.buildFilterBar();
		
		this.content.setBackground(Color.WHITE);
		
		this.buildScrollPane();
		
	}

	/**
	 * Build the filter bar with its menu and search field.
	 */
	private void buildFilterBar() {
		this.filterBar.add(this.filterMenu);
		
		this.buildFilterMenu();
		this.buildSearchField();
		
		this.c.fill = GridBagConstraints.HORIZONTAL;
		this.c.weightx = 1;
		this.c.weighty = 0;
		this.c.gridx = 0;
		this.c.gridy = 0;
		
		this.add(this.filterBar, this.c);
	}

	/**
	 * Build the scroll pane for the item browser.
	 */
	private void buildScrollPane() {
		this.c.fill = GridBagConstraints.BOTH;
		this.c.weightx = 1;
		this.c.weighty = 1;
		this.c.gridx = 0;
		this.c.gridy = 1;
		this.scrollpane = new JScrollPane(this.content);
		this.scrollpane.setVerticalScrollBarPolicy(
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		this.scrollpane.setHorizontalScrollBarPolicy(
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		this.add(this.scrollpane, this.c);
		
		/* Important note: This has to be called _AFTER_ the .add() */
		this.content.setParentScrollPane(this.scrollpane);
	}

	/**
	 * Build the menu with item filters. In this menu you can select the item
	 * slot etc.
	 */
	private void buildFilterMenu() {
		
		/*
		 * Remove the first component, the "filterMenu".
		 */
		this.filterBar.remove(0);
		
		/*
		 * Build a new menu structure.
		 */
		this.filterMenu = new JMenu();
		
		this.filterMenu.setToolTipText(
				"Show availabe items of a specific type.");
		
		this.buildArmorMenu(this.filterMenu);
		this.buildWeaponsMenu(this.filterMenu);
		this.buildModulesMenu(this.filterMenu);
		
		/*
		 * Add the new menu structure to the first component index.
		 */
		this.filterBar.add(this.filterMenu, 0);
	}

	/**
	 * Build the menu for Modules.
	 * @param items Items menu.
	 */
	private void buildModulesMenu(final JMenu items) {
		JMenu modules = new JMenu(EItemType.MODULE.toString());
		items.add(modules);
		
		for (final EModuleProficiency type 
				: EModuleProficiency.getModuleProficiencies()) {
			if (type != EModuleProficiency.POWER_CRYSTAL_1 
					&& type != EModuleProficiency.POWER_CRYSTAL_2) {
				JMenuItem moduletype = new JMenuItem(type.toString());
				modules.add(moduletype);
				moduletype.addActionListener(
						new MenuListener(type.toString(), this.filterMenu));
			}
		}
	}

	/**
	 * Build the menu for Weapons.
	 * @param items Items menu.
	 */
	private void buildWeaponsMenu(final JMenu items) {
		JMenu weapons = new JMenu(EItemType.WEAPON.toString());
		items.add(weapons);
		
		for (final EWeaponProficiency type 
				: EWeaponProficiency.getWeaponProficiencies()) {
			/*
			 * If the current specialization has the weapon proficiency, 
			 * add it to the menu.
			 */
			if (Model.getESpec().getProficiencies()
					.hasWeaponProficiency(type)) {
				JMenuItem weapontype = new JMenuItem(type.toString());
				weapons.add(weapontype);
				weapontype.addActionListener(
						new MenuListener(type.toString(), this.filterMenu));
			}
		}
	}

	/**
	 * Build the menu for Armor.
	 * @param items Items menu.
	 */
	private void buildArmorMenu(final JMenu items) {
		JMenu armor = new JMenu(EItemType.ARMOR.toString());
		items.add(armor);
		
		for (final EItemSlot slot : EItemSlot.getArmorSlots()) {
			if (slot != EItemSlot.RELIC_2 && slot != EItemSlot.IMPLANT_2) {
				JMenuItem armortype = new JMenuItem(slot.toString());
				armor.add(armortype);
				armortype.addActionListener(
						new MenuListener(slot.toString(), this.filterMenu));
			}
		}
	}

	/**
	 * Add the item search field and an invisible box to the menu bar.
	 */
	private void buildSearchField() {
		this.filterBar.add(Box.createGlue());
		final SearchField search = new SearchField(
				SEARCH_FIELD_WIDTH, SEARCH_FIELD_HEIGHT);
		this.filterBar.add(search);
	}

	@Override
	public void modelChanged(final EModelObserverEvent e) {
		if (e == EModelObserverEvent.PROFILE_LOADED) {
			this.buildFilterMenu();
			this.updateMenuTitle();
		}
		
		if (e == EModelObserverEvent.ITEM_BROWSER_MODEL_CHANGED) {
			this.updateMenuTitle();
		}
	}

	/**
	 * Update the title of the menu.
	 */
	private void updateMenuTitle() {
		final ItemBrowserModel b = Model.getProfile().getItemBrowserModel();
		final String type = b.getItemTypeCondition();
		this.filterMenu.setText(type);
	}

}
